#pragma warning(disable:4996)
#pragma warning(disable:6031)
#pragma warning(disable:6011)

namespace Y190701_matrix {
int main();

#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <assert.h>

#ifndef ElementType
#define ElementType double
#endif

typedef struct Matrix* PMatrix;
struct Matrix {
	int m;
	int n;
	int size;
	ElementType* data;
};

PMatrix matrix_init(PMatrix A, int m, int n, ElementType val)
{
	int size = m * n;
	int i;
	assert(size > 0);
	A->m = m;
	A->n = n;
	A->size = size;
	A->data = (ElementType*)malloc(sizeof(ElementType) * size);
	ElementType* dest = A->data;
	for (i = 0; i < size; i++)
		* (dest++) = val;
	return A;
}

PMatrix matrix_init(PMatrix A, int m, int n, ElementType* data) {
	int size = m * n;
	int i;
	assert(size > 0);
	if (A->size != size) {
		free(A->data);
		A->m = m;
		A->n = n;
		A->size = size;
		A->data = (ElementType*)malloc(sizeof(ElementType) * size);
	}
	ElementType* dest = A->data;
	for (i = 0; i < size; i++)
		* (dest++) = *(data++);
	return A;
}

PMatrix matrix_copy(PMatrix src, PMatrix dest) {
	assert(src->size > 0);
	int i = 0;
	if (dest->size != src->size) {
		free(dest->data);
		dest->m = src->m;
		dest->n = src->n;
		dest->size = src->size;
		dest->data = (ElementType*)malloc(sizeof(ElementType) * src->size);
	}
	if (dest->m != src->m) {
		dest->n = src->n;
		dest->m = src->m;
	}
	ElementType* d0 = dest->data, * d1 = src->data;
	for (i = 0; i < dest->size; i++)
		* (d0++) = *(d1++);
	return dest;
}

int matrix_is_same_type(PMatrix A, PMatrix B) {
	if (A && B)
		return A->m == B->m && A->n == B->n && A->size == B->size;
	return 0;
}

PMatrix matrix_add(PMatrix A, PMatrix B, PMatrix C) {
	int i = 0;
	assert(A && B);
	assert(matrix_is_same_type(A, B));
	matrix_copy(A, C);
	ElementType* d0 = C->data, * d1 = B->data;
	for (i = 0; i < A->size; i++)
		* (d0++) += *(d1++);
	return C;
}

PMatrix matrix_sub(PMatrix A, PMatrix B, PMatrix C) {
	int i = 0;
	assert(A && B);
	assert(matrix_is_same_type(A, B));
	matrix_copy(A, C);
	ElementType* d0 = C->data, * d1 = B->data;
	for (i = 0; i < A->size; i++)
		* (d0++) -= *(d1++);
	return C;
}

PMatrix matrix_mul_k(PMatrix A, ElementType k, PMatrix C) {
	int i = 0;
	assert(A && A->size > 0);
	matrix_copy(A, C);
	ElementType* d0 = C->data;
	for (i = 0; i < A->size; i++)
		* (d0++) *= k;
	return C;
}

PMatrix matrix_set(PMatrix A, int i, int j, ElementType val) {
	assert(A->size > 0);
	assert(i >= 0 && i < A->m);
	assert(j >= 0 && j < A->n);
	A->data[i * A->n + j] = val;
	return A;
}

ElementType matrix_get(PMatrix A, int i, int j) {
	assert(A->size > 0);
	assert(i >= 0 && i < A->m);
	assert(j >= 0 && j < A->n);
	return A->data[i * A->n + j];
}

void matrix_display(PMatrix A) {
	printf("%d * %d\n", A->m, A->n);
	ElementType* data = A->data;
	for (int i = 0; i < A->m; i++) {
		for (int j = 0; j < A->n; j++)
			printf("%12.3f ", *(data++));
		printf("\n");
	}
}

int main()
{
	Matrix A, B, C;
	int m = 3, n = 3;
	matrix_init(&A, m, n, 1.0);
	matrix_init(&B, m, n, 2.0);
	matrix_init(&C, m, n, 0.0);
	matrix_set(&A, 0, 0, 4);
	matrix_set(&B, 2, 2, 8);
	matrix_display(&A);
	matrix_display(&B);
	matrix_add(&A, &B, &C);
	matrix_display(&C);
	return 0;
}
}

int main_Y190701_matrix()
{
	return Y190701_matrix::main();
}